package com.gopay.checkorder.manager.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.naming.CommunicationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.gopay.checkorder.dao.BankOrderDAO;
import com.gopay.checkorder.dao.BcdlSendBankLogDAO;
import com.gopay.checkorder.dao.CheckBcdlSendBankLogDAO;
import com.gopay.checkorder.manager.BankOrderManager;
import com.gopay.common.constants.bank.BankOrderStatus;
import com.gopay.common.constants.trans.TxnStaCode;
import com.gopay.common.constants.txncd.IntTxnCd;
import com.gopay.common.cps.manager.order.CpsGeneralMainOrderQueryManager;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BcdlSendBankLog;
import com.gopay.common.domain.bank.CheckBcdlSendBankLog;
import com.gopay.common.domain.bank.CheckOrderFailLog;
import com.gopay.common.domain.bank.CheckOrderLog;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cps.vo.CheckOrderResult;
import com.gopay.common.domain.cps.vo.InAccInfo;
import com.gopay.common.order.dao.CommonQueryDAO;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.HttpTransport;
import com.gopay.common.util.RSAEncoderUtil;
import com.gopay.remote.cashier.bis.CashierBgNotifyRemoteService;
import com.gopay.common.util.StringTools;

/**
 * 
 * @BankOrderManagerImpl.java
 * @author yaobo
 * @2013-3-19 下午03:03:09 www.gopay.com.cn Inc.All rights reserved.
 */
public class BankOrderManagerImpl implements BankOrderManager {
	private final static Logger logger = LoggerFactory.getLogger("CHECK_ORDER");
	
    @Resource(name = "bankOrderDAO")
    private BankOrderDAO bankOrderDAO;
    @Resource(name = "bcdlSendBankLogDAO")
    private BcdlSendBankLogDAO bcdlSendBankLogDAO;
    
    @Resource(name = "checkBcdlSendBankLogDAO")
    private CheckBcdlSendBankLogDAO checkBcdlSendBankLogDAO;

    @Resource(name = "cpsGeneralMainOrderQueryManager")
    private CpsGeneralMainOrderQueryManager mainOrderQuery;

    @Resource(name = "cashierBgNotifyRemoteService")
    private CashierBgNotifyRemoteService cashierBgNotifyRemoteService;
    
    @Resource(name = "commonQueryDAO")
    private CommonQueryDAO commonQueryDAO;

    private String url;

    @Override
    public int lock(BankOrder bankOrder) {
        return bankOrderDAO.lock(bankOrder);
    }

    @Override
    public int unlock(BankOrder bankOrder) {
        return bankOrderDAO.unlock(bankOrder);
    }
    @Override
    public int updateTotalCheckTimes(BankOrder bankOrder) {
    	return bankOrderDAO.updateTotalCheckTimes(bankOrder);
    }

    @Override
    public void update(BankOrder bankOrder) {
        bankOrder.setLastUpdTs(DateUtils.getSystemDate());

        bankOrderDAO.update(bankOrder);
    }

    @Override
    public int updateCancel(BankOrder bankOrder) {
        bankOrder.setLastCheckBillTime(DateUtils.getSystemDate());

        return bankOrderDAO.updateCancel(bankOrder);
    }

    @Override
    public int updateFail(BankOrder bankOrder) {
        int result = bankOrderDAO.updateCheckFail(bankOrder);

        return result;
    }
    
    @Override
    public int updateEnterAccountFail(BankOrder bankOrder) {
        int result = bankOrderDAO.updateEnterAccountFail(bankOrder);

        return result;
    }
        
    @Override
    public int updateSuccess(BankOrder bankOrder, String target) {
        int result = bankOrderDAO.updateCheckSuccess(bankOrder, target);

        return result;
    }

    @Override
    public BankOrder getByGopayOutOrderId(String gopayOutOrderId) {
        return bankOrderDAO.getByGopayOutOrderId(gopayOutOrderId);
    }

    @Override
    public boolean inAcct(CheckOrderResult result) throws CommunicationException {
        boolean flag = false;

        InAccInfo accInfo = result.getAccInfo();
        if (accInfo == null) {
            return false;
        }

        // 设置发送地址
        HttpTransport httpTransport = new HttpTransport();
        httpTransport.setSendEncoding("GBK");
        httpTransport.setUrl(url);

        Map<String, String> params = new HashMap<String, String>();
        // 国付宝系统订单号
        params.put("orderId", accInfo.getOrderId());
        // 返回码
        params.put("retCode", accInfo.getRetCode());
        // 支付卡类型
        params.put("cardType", accInfo.getCardType());
        // 金额
        params.put("amt", accInfo.getAmount().toString());
        // 缓存数据生存期内银行通知次数
        params.put("notifyNum", "1");

        // 交易状态
        params.put("payStatus", "");
        // 信息描述
        params.put("retMsg", "");
        // 密文
        String sign = signRes(params);
        params.put("sign", sign);
               
        //httpTransport.submit(params);
        cashierBgNotifyRemoteService.callBgNotify(params);
        // 入账处理后获取订单状态是否为"02"
        CpsGenMainOrder mainOrder = mainOrderQuery.get(accInfo.getOrderId());
        if (mainOrder != null && mainOrder.getTxnStaCd() == TxnStaCode.TXN_STA_CD_20000.value) {
            flag = true;
        }else if(mainOrder != null && mainOrder.getTxnStaCd() == TxnStaCode.TXN_STA_CD_20005.value){//原90002 生产优化10期 lx 2017-10-19 16:49:35
        	flag = true;
        }else if(mainOrder != null&&IntTxnCd._01723.value.equals(mainOrder.getGopayIntTxnCd())&& mainOrder.getTxnStaCd() == TxnStaCode.TXN_STA_CD_30402.value){
            //跨境人民币留学汇款的订单已支付状态是30402,add by qld 20160816
            flag=true;
        }else if(mainOrder != null&&IntTxnCd._01724.value.equals(mainOrder.getGopayIntTxnCd())&& mainOrder.getTxnStaCd() == TxnStaCode.TXN_STA_CD_30402.value){
            //跨境人民币汇款的订单已支付状态是30402,add by qld 20160816
            flag=true;
        }else if(mainOrder != null&&IntTxnCd._01735.value.equals(mainOrder.getGopayIntTxnCd())&& mainOrder.getTxnStaCd() == TxnStaCode.TXN_STA_CD_30402.value){
            //跨境人民币汇款拆分支付总订单的订单已支付状态是30402,add by qld 20170511
            flag=true;
        }
        return flag;
    }
    public String signRes(Map res) {
        StringBuffer sign = new StringBuffer();
        String orderId = (String)res.get("orderId");
        String amt = (String)res.get("amt");
        String retCode = (String)res.get("retCode");
        String retMsg = (String)res.get("retMsg");
        String payStatus = (String)res.get("payStatus");
        String notifyNum = (String)res.get("notifyNum");
        String cardType = (String)res.get("cardType");
        sign.append(orderId).append("|");
        sign.append(amt).append("|");
        sign.append(retCode).append("|");
        sign.append(retMsg).append("|");
        sign.append(payStatus).append("|");
        sign.append(notifyNum).append("|");
        sign.append(cardType);
        try {
        	logger.error("bis通知cashier order: "+(String)res.get("orderId")+" plain: "+sign.toString());
            return RSAEncoderUtil.sign(sign.toString());
        } catch (Exception e) {
            logger.error("bis通知cashier Map签名异常", e);
        }
        return "";
    }

    public void setUrl(String url) {
        this.url = url;
    }

	@Override
	public void insertCheckOrderLog(CheckOrderLog checkOrderLog) {
		  bankOrderDAO.insertCheckOrderLog(checkOrderLog);
	}

	@Override
	public int updateCheckOrderLog(CheckOrderLog checkOrderLog,
			String respcode, Date checktime, int totalCheckTime) {
		 int result = bankOrderDAO.updateCheckOrderLog(checkOrderLog, respcode, checktime, totalCheckTime);

	     return result;
	}

    @Override
    public void insertCheckOrderFailLog(CheckOrderFailLog checkOrderFailLog) {
        bankOrderDAO.insertCheckOrderFailLog(checkOrderFailLog);
        
    }

    @Override
    public List getCheckOrderFailLog() {
        return bankOrderDAO.getCheckOrderFailLog();
    }
	@Override
	public List<BankOrder> getCheckOrder(Date date,
			int pageIndex, int pageSize) {
		return bankOrderDAO.getCheckOrder(date, pageIndex, pageSize);
	}


	@Override
	public int getCheckOrderCount(Date date) {
		return bankOrderDAO.getCheckOrderCount(date);
	}

	@Override
	public List<BankOrder> getGopayOrders(String bank, String date) {
		return bankOrderDAO.getGopayOrders(bank,date);
	}

    @Override
    public int updateAmountError(BankOrder bankOrder) {
        int result = bankOrderDAO.updateAmountError(bankOrder);

        return result;
    }

	@Override
	public BankOrder getByGopayOrderId(String gopayOrderId) {
		return bankOrderDAO.getByGopayOrderId(gopayOrderId);
	}


	@Override
	public int updateBankOrderId(String outOrderId, String payMsgId) {
		int result = bankOrderDAO.updateBankOrderId(outOrderId, payMsgId);
		return result;
	}

	@Override
	public void saveBcdlSendBankLog(BankOrder bankOrder) {
		BcdlSendBankLog bcdlSendBankLog = new BcdlSendBankLog();
		bcdlSendBankLog.setGopayOrderId(bankOrder.getOrderId());
		bcdlSendBankLog.setCreateTime(new Date());
		bcdlSendBankLogDAO.save(bcdlSendBankLog);
	}
	
	@Override
	public BcdlSendBankLog getLogByGopayOrderId(String gopayOrderId){
		return bcdlSendBankLogDAO.getLogByGopayOrderId(gopayOrderId);
	}

	@Override
	public void delLogByGopayOrderId(BcdlSendBankLog sendBankLog){
		bcdlSendBankLogDAO.delLogByGopayOrderId(sendBankLog);
	}


    @Override
    public Boolean isLegalTime(String bank) {
        Calendar c = Calendar.getInstance();
        int hour = c.get(Calendar.HOUR_OF_DAY); // 24小时
        int minute = c.get(Calendar.MINUTE); // 分钟

        // if (Constants.BANK_ICBC.equalsIgnoreCase(bank)) {
        // 因银行终端日期问题，23:50-00:10之间不发送银行请求
        if (hour == 23 && minute >= 50) {
            logger.error(bank + "银企直连不发送银行请求, 时间为: " + hour + ":" + minute);
            return false;
        }
        if (hour == 0 && minute < 10) {
            logger.error(bank + "银企直连不发送银行请求, 时间为: " + hour + ":" + minute);
            return false;
        }
        return true;
    }

    @Override
    public List getCheckOrderFailLog(String failCount) {
        return bankOrderDAO.getCheckOrderFailLog(failCount);
    }

	@Override
	public void saveCheckBcdlSendBankLog(BankOrder bankOrder) {
		CheckBcdlSendBankLog bcdlSendBankLog = new CheckBcdlSendBankLog();
		bcdlSendBankLog.setGopayOrderId(bankOrder.getOrderId());
		bcdlSendBankLog.setCreateTime(new Date());
		checkBcdlSendBankLogDAO.save(bcdlSendBankLog);
		
	}
	
	@Override
	@Transactional
	public void saveCheckBcdlSendBankLogByOrderIds(List<String> orderIds) {
		for (String orderId : orderIds) {
			logger.error("插入发往银行日志--开始,gopayOrderId=" + orderId);
			CheckBcdlSendBankLog bcdlSendBankLog = new CheckBcdlSendBankLog();
			bcdlSendBankLog.setGopayOrderId(orderId);
			bcdlSendBankLog.setCreateTime(new Date());
			checkBcdlSendBankLogDAO.save(bcdlSendBankLog);
			logger.error("插入发往银行日志--结束,gopayOrderId=" + orderId);
		}
		
	}
	
	@Override
	@Transactional
	public void saveCheckBcdlSendBankLogByOrders(List<BankOrder> orders) {
		for (BankOrder order : orders) {
			logger.error("插入发往银行日志--开始,gopayOrderId=" + order.getOrderId());
			CheckBcdlSendBankLog bcdlSendBankLog = new CheckBcdlSendBankLog();
			bcdlSendBankLog.setGopayOrderId(order.getOrderId());
			bcdlSendBankLog.setCreateTime(new Date());
			checkBcdlSendBankLogDAO.save(bcdlSendBankLog);
			logger.error("插入发往银行日志--结束,gopayOrderId=" + order.getOrderId());
		}
		
	}

	@Override
	public BankOrder getSendOneTestOrder(String sentinelCode) {
		List<Object[]> list = getSendOneTestOrderBySenCode(sentinelCode, BankOrderStatus.ACCEPTED);
		if(CollectionUtils.isEmpty(list)){
			return null;
		}
		String bankOrderId = StringTools.checkNulltoString(list.get(0));
		BankOrder bankOrder = bankOrderDAO.find(BankOrder.class, bankOrderId);
		return bankOrder;
	}
	
	@Override
	public BankOrder getCheckOneTestOrder(String sentinelCode) {
		List<Object[]> list = getSendOneTestOrderBySenCode(sentinelCode, BankOrderStatus.PROCESS);
		if(CollectionUtils.isEmpty(list)){
			return null;
		}
		String bankOrderId = StringTools.checkNulltoString(list.get(0));
		BankOrder bankOrder = bankOrderDAO.find(BankOrder.class, bankOrderId);
		return bankOrder;
	}

	public List<Object[]> getSendOneTestOrderBySenCode(String sentinelCode, String orderStatus){
    	StringBuffer sql = new StringBuffer(250);
    	sql.append("select b.gopay_order_id from bis_one_fen_test_order b ");
    	sql.append(" left join bis_bank_main_order m ");
    	sql.append(" on b.gopay_order_id = m.gopay_order_id ");
    	sql.append(" where b.sentinel_code = :sentinelCode ");
    	sql.append(" and m.order_status = :orderStatus ");
    	sql.append(" order by b.created_ts desc ");
    	
    	Map<String, Object> params = new HashMap<String, Object>();
    	params.put("sentinelCode", sentinelCode);
    	params.put("orderStatus", orderStatus);
    	List<Object[]> list = commonQueryDAO.findBySql(sql.toString(), params, 1, 10);
    	return list;
    }
}
